{
 "cells": [
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 练习决策树",
   "id": "15ad38eba926ddbc"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 数据预处理",
   "id": "37df6136dc773b78"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-02T11:43:44.052504Z",
     "start_time": "2025-03-02T11:43:43.259131Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from sklearn.model_selection import train_test_split, GridSearchCV\n",
    "from sklearn.feature_extraction import DictVectorizer\n",
    "from sklearn.tree import DecisionTreeClassifier, export_graphviz\n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "import pandas as pd\n",
    "import numpy as np"
   ],
   "id": "330f83c28aaa1ba9",
   "outputs": [],
   "execution_count": 1
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-02T11:43:44.061379Z",
     "start_time": "2025-03-02T11:43:44.052504Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 泰坦尼克号数据集\n",
    "titanic = pd.read_csv('titanic.txt')\n",
    "titanic.head()\n",
    "titanic.info()  # 查看数据信息，能看到有很多缺失值，所以要对数据进行处理"
   ],
   "id": "e8bdd920d01df1ed",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 1313 entries, 0 to 1312\n",
      "Data columns (total 11 columns):\n",
      " #   Column     Non-Null Count  Dtype  \n",
      "---  ------     --------------  -----  \n",
      " 0   row.names  1313 non-null   int64  \n",
      " 1   pclass     1313 non-null   object \n",
      " 2   survived   1313 non-null   int64  \n",
      " 3   name       1313 non-null   object \n",
      " 4   age        633 non-null    float64\n",
      " 5   embarked   821 non-null    object \n",
      " 6   home.dest  754 non-null    object \n",
      " 7   room       77 non-null     object \n",
      " 8   ticket     69 non-null     object \n",
      " 9   boat       347 non-null    object \n",
      " 10  sex        1313 non-null   object \n",
      "dtypes: float64(1), int64(2), object(8)\n",
      "memory usage: 113.0+ KB\n"
     ]
    }
   ],
   "execution_count": 2
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "先找出特征和目标值，方便后续处理",
   "id": "e976bec66b9ad69a"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-02T11:43:44.067492Z",
     "start_time": "2025-03-02T11:43:44.061379Z"
    }
   },
   "cell_type": "code",
   "source": [
    "x = titanic[['pclass', 'age', 'sex']]\n",
    "y = titanic['survived']\n",
    "# 这里age特征很明显有缺失值，所以先用平均值填充\n",
    "print(type(x))\n",
    "# 用loc取出、填充缺失值,loc是根据索引来取值，这里的索引是'age'\n",
    "x.loc[:, 'age'] = x.loc[:, 'age'].fillna(x.loc[:, 'age'].mean())\n",
    "x.info()  # 查看数据信息，age特征缺失值已经处理完毕"
   ],
   "id": "236715b9b48ff1a0",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 1313 entries, 0 to 1312\n",
      "Data columns (total 3 columns):\n",
      " #   Column  Non-Null Count  Dtype  \n",
      "---  ------  --------------  -----  \n",
      " 0   pclass  1313 non-null   object \n",
      " 1   age     1313 non-null   float64\n",
      " 2   sex     1313 non-null   object \n",
      "dtypes: float64(1), object(2)\n",
      "memory usage: 30.9+ KB\n"
     ]
    }
   ],
   "execution_count": 3
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "分割数据集",
   "id": "b932cc140f8c0d92"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-02T11:43:44.075641Z",
     "start_time": "2025-03-02T11:43:44.067492Z"
    }
   },
   "cell_type": "code",
   "source": [
    "x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25, random_state=4)\n",
    "print(x_train.head())  # x_train数据集还需要进行特征编码\n",
    "print('-' * 50)\n",
    "print(sum(x_train['sex'] == 'female'))\n",
    "print(sum(x_train['sex'] == 'male'))  # 男女性别比例\n",
    "print('-' * 50)\n",
    "print(y_train.value_counts())"
   ],
   "id": "318812e8c0df73bd",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "    pclass        age     sex\n",
      "598    2nd  30.000000    male\n",
      "246    1st  62.000000    male\n",
      "905    3rd  31.194181  female\n",
      "300    1st  31.194181  female\n",
      "509    2nd  64.000000    male\n",
      "--------------------------------------------------\n",
      "341\n",
      "643\n",
      "--------------------------------------------------\n",
      "survived\n",
      "0    650\n",
      "1    334\n",
      "Name: count, dtype: int64\n"
     ]
    }
   ],
   "execution_count": 4
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 特征工程",
   "id": "acf67a6f9255e982"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-02T11:43:44.082325Z",
     "start_time": "2025-03-02T11:43:44.075641Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 特征编码\n",
    "dvc = DictVectorizer(sparse=False)\n",
    "x_train = dvc.fit_transform(x_train.to_dict(orient='records'))\n",
    "x_test = dvc.transform(x_test.to_dict(orient='records'))"
   ],
   "id": "2f5edbb594c99ae3",
   "outputs": [],
   "execution_count": 5
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "",
   "id": "313588386326983"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-02T11:43:44.086039Z",
     "start_time": "2025-03-02T11:43:44.082325Z"
    }
   },
   "cell_type": "code",
   "source": [
    "print(x_train)\n",
    "print('-' * 50)\n",
    "print(dvc.get_feature_names_out())  # 特征名对应one-hot编码的列"
   ],
   "id": "dd4ac5b949c8583",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[30.          0.          1.          0.          0.          1.        ]\n",
      " [62.          1.          0.          0.          0.          1.        ]\n",
      " [31.19418104  0.          0.          1.          1.          0.        ]\n",
      " ...\n",
      " [34.          0.          1.          0.          0.          1.        ]\n",
      " [46.          1.          0.          0.          0.          1.        ]\n",
      " [31.19418104  0.          0.          1.          0.          1.        ]]\n",
      "--------------------------------------------------\n",
      "['age' 'pclass=1st' 'pclass=2nd' 'pclass=3rd' 'sex=female' 'sex=male']\n"
     ]
    }
   ],
   "execution_count": 6
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 机器学习模型训练",
   "id": "6b231f6c0614d9d9"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-02T11:43:44.096373Z",
     "start_time": "2025-03-02T11:43:44.086039Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 决策树模型\n",
    "dtc = DecisionTreeClassifier(criterion='gini', max_depth=7)  # 默认算法是gini\n",
    "dtc.fit(x_train, y_train)\n",
    "print('训练集准确率:', dtc.score(x_train, y_train))\n",
    "# 导出决策树\n",
    "export_graphviz(dtc, out_file=\"tree.dot\",\n",
    "                feature_names=['年龄', 'pclass=1st', 'pclass=2nd', 'pclass=3rd', '女性', '男性'])"
   ],
   "id": "52bc8b7b4a6196fe",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练集准确率: 0.8526422764227642\n"
     ]
    }
   ],
   "execution_count": 7
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "",
   "id": "e3a1821c98a083a4"
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "调整模型参数",
   "id": "f5f5a26670d567ec"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-02T11:43:44.100784Z",
     "start_time": "2025-03-02T11:43:44.096373Z"
    }
   },
   "cell_type": "code",
   "source": [
    "dtc = DecisionTreeClassifier(criterion='entropy', max_depth=3, min_impurity_decrease=0.001)  # 调整参数, 最大深度为10，最小不纯度下降为0.01，每个结点所包含的最少样本数参数设置：min_samples_split=2\n",
    "dtc.fit(x_train, y_train)\n",
    "print('训练集准确率:', dtc.score(x_train, y_train))"
   ],
   "id": "ad529c2aa4e7fcf",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练集准确率: 0.823170731707317\n"
     ]
    }
   ],
   "execution_count": 8
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 模型优化",
   "id": "448947856f5b3837"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-02T11:43:44.268158Z",
     "start_time": "2025-03-02T11:43:44.100784Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from sklearn.model_selection import GridSearchCV\n",
    "\n",
    "# 定义参数网格\n",
    "param_grid = {\n",
    "    'criterion': ['gini', 'entropy'],\n",
    "    'max_depth': [3,5, 7, 10, 15],\n",
    "    'min_impurity_decrease': [0.001, 0.05, 0.01]\n",
    "}\n",
    "# 实例化模型\n",
    "gc = GridSearchCV(DecisionTreeClassifier(), param_grid, cv=5)\n",
    "# 使用 GridSearchCV 进行调参\n",
    "gc.fit(x_train, y_train)\n",
    "# 输出最佳参数和准确率\n",
    "\n",
    "print('最佳参数:', gc.best_params_)\n",
    "print('最佳模型准确率:', gc.best_score_)"
   ],
   "id": "cec39488f73dce79",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最佳参数: {'criterion': 'entropy', 'max_depth': 5, 'min_impurity_decrease': 0.001}\n",
      "最佳模型准确率: 0.8242100901274215\n"
     ]
    }
   ],
   "execution_count": 9
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
